﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Shapes = System.Windows.Shapes;
using FeatureModelCore;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Media;
using FeatureModelCore.FMShapes;
using System.Windows.Input;
using FeatureModelCore.FMTypes;
using FeatureModelTool.FMAlgorithms;
using FeatureModelTool.FMAlgorithms.FMGraphicAlgorithms;
using FeatureModelCore.Layout;
using FeatureModelCore.FMInterface;

namespace FeatureModelTool.FeatureModelGraphical.GraphicalControls
{
    public class Control_GroupRelationship: IControl
    {
        public readonly static Brush COMMON_COLOR = Brushes.LemonChiffon;
        public readonly static int DEFAULT_ANGLE_THICKNESS = 5;

        #region Properties
        public FeatureTreeGroupRelationship FeatureInstance { get { return _gRelationship; } }
        public FeatureModelGraphicalView Canvas { get { return _canvas; } }
        public bool IsFocus { get { return _isFocus; } }
        public Brush Background { get { return COMMON_COLOR; } }

        public int BorderThickness
        {
            get
            {
                if (_isFocus)
                    return FeatureModelGraphicalView.FOCUS_THICKNESS;
                return FeatureModelGraphicalView.DEFAULT_THICKNESS;
            }
        }
        #endregion


        #region Fields
        private FeatureTreeGroupRelationship _gRelationship;
        private FeatureModelGraphicalView _canvas;
        private bool _isFocus;

        private Path _circleGraphic;
        private Path _angleGraphic;

        private bool _isPressed;
        private FMPoint _orgPlace;

        private List<Control_Relationship> _lines;
        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="groupRelationship"></param>
        public Control_GroupRelationship(FeatureModelGraphicalView canvas,
            FeatureTreeGroupRelationship groupRelationship)
        {
            _canvas = canvas;
            _gRelationship = groupRelationship;
            _isFocus = false;

            _isPressed = false;
            _orgPlace = new FMPoint(0, 0);

            _circleGraphic = new Path();
            _angleGraphic = new Path();
            #region set circle
            FMCircle shape = this.FeatureInstance.Shape;
            EllipseGeometry ellipse = new EllipseGeometry(new Point(0, 0),
                this.FeatureInstance.Shape.Radius, shape.Radius);
            _circleGraphic.Data = ellipse;

            _circleGraphic.Fill = Background;
            _circleGraphic.Stroke = Control_TreeNode.COMMON_STROKE_COLOR;
            _circleGraphic.StrokeThickness = BorderThickness;

            #endregion

            _lines = new List<Control_Relationship>();
            foreach (FeatureTreeNode node in _gRelationship.ChildrenNodes)
            {
                _lines.Add(new Control_Relationship(canvas
                    , _gRelationship, node));
            }

            RefreshPosition();

            #region Mouse Event Handler
            _circleGraphic.MouseLeftButtonDown += new MouseButtonEventHandler(MouseLeftClickDown);
            _circleGraphic.MouseLeftButtonUp += new MouseButtonEventHandler(MouseLeftClickUp);
            _circleGraphic.MouseMove += new MouseEventHandler(MouseMove);
            #endregion
        }

        /// <summary>
        /// Generate UI Element
        /// </summary>
        /// <returns></returns>
        public UIElement[] ToUIElement()
        {
            List<UIElement> uiElems = new List<UIElement>();
            foreach (Control_Relationship line in _lines)
            {
                uiElems.AddRange(line.ToUIElement());
            }
            uiElems.Add(_circleGraphic);
            if (_gRelationship.Type == FMTreeGroupRelationshipType.GroupMandatory
                || _gRelationship.Type == FMTreeGroupRelationshipType.GroupOptional)
            {
                
                return uiElems.ToArray<UIElement>();
            }

            FMCircle shape = _gRelationship.Shape;

            uiElems.Add(_angleGraphic);
            return uiElems.ToArray<UIElement>();
        }

        #region Focus
        /// <summary>
        /// Set Focus
        /// </summary>
        public void Focus()
        {
            this._canvas.ClearFocus();
            this._isFocus = true;

            _canvas.Refresh(this, null);
        }
        /// <summary>
        /// Clear Focus
        /// </summary>
        public void ClearFocus()
        {
            _isFocus = false;
        }
        #endregion

        #region Mouse Event Hanlder
        /// <summary>
        /// Mouse Move
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void MouseMove(object sender, MouseEventArgs args)
        {
            if (args.LeftButton != MouseButtonState.Pressed)
            {
                return;
            }
            if (_isPressed == false
                || _orgPlace == null)
            {
                return;
            }

            Point curPt = args.MouseDevice.GetPosition(this._canvas);
            double curMouseX, curMouseY;
            curMouseX = curPt.X;
            curMouseY = curPt.Y;

            double orgMouseX, orgMouseY;
            lock (_orgPlace)
            {
                orgMouseX = _orgPlace.X;
                orgMouseY = _orgPlace.Y;

                // reset org place
                _orgPlace = new FMPoint(curMouseX, curMouseY);
            }

            double orgShapeX, orgShapeY;
            orgShapeX = _gRelationship.Shape.Center.X;
            orgShapeY = _gRelationship.Shape.Center.Y;

            double curShapeX = curMouseX - orgMouseX + orgShapeX;
            double curShapeY = curMouseY - orgMouseY + orgShapeY;

            this.SetPosition(curShapeX, curShapeY, true);
        }

        /// <summary>
        /// Mouse Left Click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void MouseLeftClickDown(object sender, MouseButtonEventArgs args)
        {
            // set move information
            Point pt = args.MouseDevice.GetPosition(this._canvas);
            this._orgPlace = new FMPoint(pt.X, pt.Y);
            this._isPressed = true;

            // set focus
            this.Focus();

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void MouseLeftClickUp(object sender, MouseButtonEventArgs args)
        {
            _isPressed = false;
        }
        #endregion

        #region Set Position
        public void SetPosition(FMPoint point, bool toRefresh)
        {
            SetPosition(point.X, point.Y, toRefresh);
        }

        public void SetPosition(double x, double y, bool toRefresh)
        {
            double top = TreeLayout.MARGIN + TreeLayout.DEFAULT_RADIUS;
            double left = TreeLayout.MARGIN + TreeLayout.DEFAULT_RADIUS;

            if (y < top)
            {
                y = top;
            }
            if (x < left)
            {
                x = top;
            }
            double radius = _gRelationship.Shape.Radius;
            _gRelationship.Shape = new FMCircle(radius, new FMPoint(x, y));
            

            if (toRefresh) _canvas.RefreshPosition(this, null);
        }
        #endregion

        public void RefreshPosition()
        {
            foreach (Control_Relationship line in _lines)
            {
                line.RefreshPosition();
            }

            FMCircle shape = _gRelationship.Shape;
            _circleGraphic.Margin = new Thickness(shape.Center.X
                    , shape.Center.Y, 0, 0);

            if (_gRelationship.Type == FMTreeGroupRelationshipType.GroupMandatory
                || _gRelationship.Type == FMTreeGroupRelationshipType.GroupOptional)
            {
                _angleGraphic.Data = null;
                return;
            }

            #region Angle
            double centerX = _gRelationship.Shape.Center.X;
            double centerY = _gRelationship.Shape.Center.Y + shape.Radius;
            FMPoint centerA = new FMPoint(centerX, centerY);

            // get all group relationships
            IFeature[] childrenNode = _gRelationship.ChildrenNodes;
            List<FMPoint> pointList = new List<FMPoint>();
            foreach (FeatureTreeNode node in childrenNode)
            {
                double x = node.Shape.Center.X;
                double y = node.Shape.Center.Y - node.Shape.Height / 2 - Control_Relationship.DEFAULT_RADIUS;
                pointList.Add(new FMPoint(x, y));
            }

            bool clockwise;
            bool isLarge;
            FMPoint startPoint, endPoint;
            double lineLength = DEFAULT_ANGLE_THICKNESS * 2;

            bool isFill = false;
            if (_gRelationship.Type == FMTreeGroupRelationshipType.Or)
            {
                isFill = true;
            }
            if (isFill)
            {
                lineLength = DEFAULT_ANGLE_THICKNESS;
            }

            // calculate angle graphic parameters
            GraphicAngleAlgorithms.CalculateCoverAngle
                (centerA, pointList.ToArray<FMPoint>()
                , lineLength, out clockwise, out isLarge, out startPoint, out endPoint);

            // generate figure instance
            ArcSegment _arcSegment = new ArcSegment(); // for angle
            PathFigure _pathFigure = new PathFigure();
            PathGeometry _pathGeometry = new PathGeometry();
            _arcSegment = new ArcSegment();
            _pathFigure = new PathFigure();
            _pathFigure.Segments.Add(_arcSegment);
            _pathGeometry = new PathGeometry();
            _pathGeometry.Figures.Add(_pathFigure);
            

            if (clockwise)
            {
                _arcSegment.SweepDirection = SweepDirection.Clockwise;
            }
            else
            {
                _arcSegment.SweepDirection = SweepDirection.Counterclockwise;
            }

            _arcSegment.Point = new Point(endPoint.X, endPoint.Y);
            _arcSegment.RotationAngle = 0;
            _arcSegment.IsStroked = true;
            _arcSegment.IsLargeArc = isLarge;
            _arcSegment.Size = new Size(lineLength, lineLength);
            _angleGraphic.Stroke = Brushes.Black;
            _pathFigure.StartPoint = new Point(startPoint.X, startPoint.Y);
            if (isFill)
            {
                _angleGraphic.StrokeThickness = DEFAULT_ANGLE_THICKNESS * 2;
            }
            else
            {
                _angleGraphic.StrokeThickness = FeatureModelGraphicalView.DEFAULT_THICKNESS;
            }

            _angleGraphic.Data = _pathGeometry;
            #endregion


        }
    }
}
